package utiltool

import (
	"errors"
	"gitee.com/dennis-kk/rpc-go-backend/idlrpc/net"
	"gitee.com/dennis-kk/rpc-go-backend/idlrpc/transport"
	"sync"
	"sync/atomic"
)

//TODO using ring buffer 替代

var (
	transCount uint32
	transMap   map[uint32]*MockTrans
	randcount  uint32
	once       sync.Once
)

type MockTrans struct {
	transID    uint32
	isclose    uint32
	recvbuffer []byte
	conn       net.IdlConn //网络层实际使用的连接
}

func NewMockTrans(conn net.IdlConn) *MockTrans {
	transCount++
	trans := &MockTrans{
		transID: transCount,
		isclose: transport.TRANS_WORKING,
		conn:    conn,
	}

	transMap[trans.transID] = trans
	return trans
}

func GetTrans(transid uint32) *MockTrans {
	trans, ok := transMap[transid]
	if !ok {
		return nil
	}
	return trans
}

func GetRandomTrans() *MockTrans {
	count := uint32(0)
	for _, v := range transMap {
		if count == randcount {
			randcount = (randcount + 1) % uint32(len(transMap))
			return v
		}
		count++
	}

	return nil
}

func init() {
	once.Do(func() {
		transCount = 1
		transMap = make(map[uint32]*MockTrans)
		listeners = make(map[uint64]*MockAccept)
		connecter = make(map[uint64]*MockConnect)
	})
}

func (trans *MockTrans) Wirte(pkg []byte, length int) (int, error) {
	trans.recvbuffer = append(trans.recvbuffer, pkg...)
	return len(trans.recvbuffer), nil
}
func (trans *MockTrans) Read(pkg []byte, length int) (int, error) {
	if len(trans.recvbuffer) < length {
		return 0, nil
	}
	real := copy(pkg, trans.recvbuffer[:length])
	if real != length {
		//TODO 添加报错
		return 0, nil
	}
	trans.recvbuffer = trans.recvbuffer[length:]
	return length, nil
}
func (trans *MockTrans) Peek(length int) ([]byte, int, error) {
	if trans == nil {
		return nil, 0, errors.New("Messags Trans Errror !!!!!")
	}

	if len(trans.recvbuffer) < length {
		return nil, len(trans.recvbuffer), nil
	}
	return trans.recvbuffer[:length], length, nil
}
func (trans *MockTrans) Send(pkg []byte) error {
	if trans == nil {
		return errors.New("transport is not valid !!!!")
	}

	if trans.conn == nil {
		return errors.New("conn is invalid !!!!")
	}

	trans.conn.Send(pkg)
	return nil
}

func (trans *MockTrans) Close() {
	//flush 标志位
	atomic.StoreUint32(&trans.isclose, 1)
}
func (trans *MockTrans) Size() uint32 {
	return uint32(len(trans.recvbuffer))
}
func (trans *MockTrans) IsClose() bool {
	return atomic.LoadUint32(&trans.isclose) == transport.TRANS_CLOSED
}
func (trans *MockTrans) GetID() uint32 {
	return trans.transID
}

func (trans MockTrans) SetID(transID uint32) {
	trans.transID = transID
}
